#include "SurfaceBuilder.h"


SurfaceBuilder::SurfaceBuilder(std::unique_ptr<Algoritmo2D> ptrAlgo2D) : 
	m_generadorPuntos( std::move(ptrAlgo2D) ), 
	m_helper( m_generadorPuntos->getLimiteInferior(), m_generadorPuntos->getLimiteSuperior() )
{
}


SurfaceBuilder::~SurfaceBuilder(){
}


void SurfaceBuilder::addCurvaControl( std::vector< glm::vec3 > vecVertices ) {
	this->m_generadorPuntos->addCurvaControl( vecVertices );
}


// La superficie es cuadrada en relacion a la cantidad de pasos
void SurfaceBuilder::buildCurva(unsigned int cantPts_U, unsigned int cantPts_V){
	// Construye todos los elementos y despues los comitea
	std::vector<glm::vec3> vertices = buildVertices(cantPts_U, cantPts_V);

	std::vector<unsigned int> indexBuff = this->m_helper.buildIndexBuffer(cantPts_U, cantPts_V);
	std::vector<glm::vec3> normales = this->m_helper.buildNormales(cantPts_U, vertices);
	std::vector<glm::vec2> coordsTextura = this->m_helper.buildCoordsTextura(cantPts_U, cantPts_V);

	// Se guardan los resultados
	this->m_vecVertices.swap( vertices );
	this->m_indexBuffer.swap( indexBuff );
	this->m_vecNormales.swap( normales );
	this->m_vecCoordsTextura.swap( coordsTextura );
}


std::vector< glm::vec3 > SurfaceBuilder::buildVertices(unsigned int cantHorizontal, unsigned int cantVertical) const {
	// Los limites
	const float limiteSup = this->m_generadorPuntos->getLimiteSuperior();
	const float limiteInf = this->m_generadorPuntos->getLimiteInferior();

	const float tamPasoU = static_cast<float>( (limiteSup - limiteInf) / (cantHorizontal -1) );
	const float tamPasoV = static_cast<float>( (limiteSup - limiteInf) / (cantVertical -1) );

	// Construye los vectices
	std::vector< glm::vec3 > vTemp;

	for (unsigned int j = 0; j < cantVertical; ++j){
		for (unsigned int i = 0; i < cantHorizontal; ++i){
			const float u = limiteInf + i * tamPasoU;
			const float v = limiteInf + j * tamPasoV;

			glm::vec3 punto = this->m_generadorPuntos->eval(u, v);
			vTemp.push_back( punto );
		}
	}

	return vTemp;
}


std::vector< glm::vec3 > SurfaceBuilder::getVertices() const {
	return this->m_vecVertices;
}


std::vector< glm::vec3 > SurfaceBuilder::getNormales() const {
	return this->m_vecNormales;
}


std::vector< unsigned int > SurfaceBuilder::getIndexBuffer() const {
	return this->m_indexBuffer;
}


std::vector< glm::vec2 > SurfaceBuilder::getCoordenadasTextura() const {
	return this->m_vecCoordsTextura;
}


